<?php
namespace StoreAdmin\Controller;

use Think\Controller;

import('Vendor.OpenWechat.wxBizMsgCrypt', '', '.php');
import('Vendor.OpenWechat.OpenWechat');
import('Vendor.OpenWechat.TpOpenWechat');
class OpenWechatDispatcherController extends Controller
{

    /**
     * 配置基础参数
     * @var string
     */
    private $component_appid          = 'wx62532abac970089e';
    private $component_appsecret      = '3d105be4e77b8aec0ca6b52a44d4aa62';
    private $component_encodingAesKey = '9818af84da6f96579e99ed315f69e0c5da6f96579ea';
    private $component_token          = 'FhUVBUpuMkZd';
    private $curl_headers;

    /**
     * @return 扫码页
     */
    public function index()
    {
        $companyuid = I('get.companyuid');
        $limit = D('member_company')->where(array('uid'=>$companyuid))->getField('wx_num');
 
        $has = D('wechat')->where(array('company_uid'=>$companyuid))->count();
        
        if($limit>0 && $has>=$limit ){
            $this->error('对不起，您只能创建'.$limit.'个公众号，请联系管理员！');
        }

       
        $link       = $this->getAuthLlink($companyuid);
        $this->assign('link', $link);
        $this->display();
    }

    /**
     * @param  获取授权链接
     * @return string 网址
     */
    private function getAuthLlink($companyuid)
    {

        $pre_auth_code = $this->getPrecode();
        if (!$pre_auth_code) {
            $this->error('预授权码无法获取，请更新缓存！');
        }
        $redirect_uri = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . '/openWechat/authCallback?companyuid=' . $companyuid;
        $redirect_uri = urlencode($redirect_uri);
        $auth_type    = 1;
        if (isMobileVisit()) {
            $href = 'https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&no_scan=1&component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=%s#wechat_redirect';
            $href = sprintf($href, $this->component_appid, $pre_auth_code, $redirect_uri, $auth_type);
        } else {
            $href = 'https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=%s';
            $href = sprintf($href, $this->component_appid, $pre_auth_code, $redirect_uri, $auth_type);

        }
        return $href;
    }

    /**
     * @return 获取预授权码
     */
    private function getPrecode()
    {
        $precode = S('pre_auth_code');
        if (!$precode) {
            $url  = 'https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=' . $this->getComponentAccessToken();
            $data = array(
                'component_appid' => $this->component_appid,
            );
            $r = curlRequest($url, $data);
            if ($r) {
                $r       = json_decode($r, true);
                $precode = $r['pre_auth_code'];
                if (!$precode) {
                    S('componentAccessToken', null);
                    $this->error('预授权码获取失败，' . $r['errmsg']);
                }
                S('pre_auth_code', $precode, 500);
            }

        }
        return $precode;

    }

    /**
     * @return 获取第三方授权令牌
     */
    private function getComponentAccessToken()
    {
        try {
            $token = S('componentAccessToken');
            if (!$token) {
                $ticket = $this->getTicket();
                $url    = 'https://api.weixin.qq.com/cgi-bin/component/api_component_token';
                $data   = array(
                    'component_appid'         => $this->component_appid,
                    'component_appsecret'     => $this->component_appsecret,
                    'component_verify_ticket' => $ticket,
                );

                $r = curlRequest($url, $data);
                if ($r) {
                    $r     = json_decode($r, true);
                    $token = $r['component_access_token'];
                    S('componentAccessToken', $token, 7000);
                }

            }
            if (!$token) {
                throw new \Exception("access_token获取失败，" . $r['errmsg']);

            }
            return $token;

        } catch (Exception $e) {
            $this->error($e->getMessage());

        }
    }

    /**
     * @return 获取ticket推送，取消第三方授权通知等
     */
    public function message()
    {

        $get = I('get.');

        $pc = new \WXBizMsgCrypt($this->component_token, $this->component_encodingAesKey, $this->component_appid);

        $timeStamp  = $get['timestamp'];
        $msg_sign   = $get['msg_signature'];
        $nonce      = $get['nonce'];
        $encryptMsg = file_get_contents('php://input');

        $msg = '';

        $errCode = $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $encryptMsg, $msg);

        if ($errCode == 0) {
            $des = xmlToArr($msg);
            switch ($des['InfoType']) {
                case 'component_verify_ticket':
                    $ticket = $des['ComponentVerifyTicket'];
                    F('ComponentVerifyTicket', null);
                    $ex  = D('WechatTicket')->where(array('id' => 1))->find();
                    $now = date('Y-m-d H:i:s');
                    if (!$ex) {
                        D('WechatTicket')->add(array('created' => $now, 'ticket' => $ticket));
                    } else {
                        D('WechatTicket')->where(array('id' => 1))->save(array('created' => $now, 'ticket' => $ticket));

                    }
                    echo 'success';
                    exit;
                    break;

            }

        } else {
            \Think\Log::record('--e---');
            \Think\Log::record($errCode);
        }

    }

    /**
     * @return 获取系统内ticket，根据第三方推送的ticket得到
     */
    private function getTicket()
    {
        $ticket = F('ComponentVerifyTicket');
        if (!$ticket) {
            $ticket = D('WechatTicket')->where(array('id' => 1))->getField('ticket');
            F('ComponentVerifyTicket', $ticket);
        }
        if (!$ticket) {
            $this->error('ticket获取失败！');
        }
        return $ticket;

    }

    /**
     * @return 代执行接口
     */
    public function callback()
    {
        try {

            $appid = I('get.appid');
            if (!$appid) {
                throw new \Exception("no appid");
            }

            $info = D('WechatOpen')->where("authorizer_appid='" . $appid . "'")->find();
            if (!$appid) {
                throw new \Exception("no such wechat by" . $appid);
            }

            $options = array(
                'appid'                    => $info['authorizer_appid'], //填写高级调用功能的密钥

                'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
                'component_token'          => $this->component_token, //填写高级调用功能的密钥
                'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
                'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
            );

            $wechat = \TPOpenWechat::getInstance($options);
            $wechat->valid(false);

            $this->doRec($appid, $wechat);

        } catch (Exception $e) {
            $this->error($e->getMessage);
        }

    }

    /**
     * 消息接收处理
     * @param  [type]
     * @param  [type]
     * @return [type]
     */
    private function doRec($appid, &$wechat)
    {

        $wechat_info = D('Wechat')->where(array('wechat_appid' => $appid))->field('id,company_uid,wechat_state,is_third_auth')->find();
        if(!$wechat_info['is_third_auth']){
            return false;
        }
        if (!$wechat_info['wechat_state']) {
            return false;
        }

        $type    = $wechat->getRev()->getRevType();
        $message = $wechat->getRev()->getRevData();
        $openid  = $message['FromUserName'];
        $wechat->setProperty(array(
            'message'     => $message,
            'openid'      => $openid,
            'wechat_info' => $wechat_info,
        ));
        D('WechatMessage')->add(array(
            'info_type' => $type,
            'message'   => json_encode($message, JSON_UNESCAPED_UNICODE),
            'created'   => date('Y-m-d H:i:s'),
            'openid'    => $openid,
            'wechat_id' => $wechat_info['id'],
        ));

        switch ($type) {
            case $wechat::MSGTYPE_TEXT:
                //全网测试
                $content = trim($wechat->getRev()->getRevContent());
                if ($content == 'TESTCOMPONENT_MSG_TYPE_TEXT') {
                    $wechat->text('TESTCOMPONENT_MSG_TYPE_TEXT_callback')->reply();
                    exit;
                }
                //全网测试
                if (strpos($content, 'QUERY_AUTH_CODE') !== false) {
                    $wechat->text(' ')->reply();
                    $auth_code = str_replace('QUERY_AUTH_CODE:', '', $content);
                    $data      = array(
                        'component_appid'    => $this->component_appid,
                        'authorization_code' => $auth_code,
                    );
                    $r = curlRequest('https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=' . $this->getComponentAccessToken(), $data);
                    if ($r) {
                        $r = json_decode($r, true);
                        //入库
                        D('WechatOpen')->saveAuthor($r);
                        //初始单公众号缓存
                        $appid    = $r['authorization_info']['authorizer_appid'];
                        $authname = 'wechat_access_token' . $appid;
                        //创建token缓存
                        S($authname, $r['authorization_info']['authorizer_access_token'], 7000);

                        //保存公众号信息
                        $wechatInfo               = $this->getWechatInfo($appid);
                        $wechatInfo['companyuid'] = $companyuid;
                        $wechatInfo && D('WechatOpen')->saveWechat($wechatInfo);

                        $info_send = array(
                            'touser'  => $openid,
                            'msgtype' => 'text',
                            'text'    => array('content' => $auth_code . '_from_api'),
                        );

                        $s = $wechat->sendCustomMessage($info_send);

                    }
                    exit;
                }
                $extw             = '';
                $content && $extw = "FIND_IN_SET('" . $content . "',tag) ";
                $replys           = $this->buildMessage($wechat, $extw);
                $replys && $this->sendMultipleMessage($wechat, $replys);
                !$replys && $this->doNoMessage($wechat);
                break;
            case $wechat::MSGTYPE_EVENT:
                $this->doEvent($wechat);
                break;
            case $wechat::MSGTYPE_LOCATION:
                $this->doLocation($wechat);
                break;
            default:

        }

    }

    /**
     * @param  地理位置上报处理，被动接收
     * @return [type]
     */
    private function doLocation(&$wechat)
    {
        $message     = $wechat->getProperty('message');
        $wechat_info = $wechat->getProperty('wechat_info');
        $openid      = $wechat->getProperty('openid');
        $position    = $message['Location_X'] . ',' . $message['Location_Y'];
        D('WechatFans')->where(array('openid' => $openid))->save(array('position' => $position));

    }

    /**
     * 地理位置处理，来自菜单推送
     * @param  [type]
     * @return [type]
     */
    private function doEventLocation(&$wechat)
    {
        $message     = $wechat->getProperty('message');
        $wechat_info = $wechat->getProperty('wechat_info');
        $openid      = $wechat->getProperty('openid');
        $position    = $message['Latitude'] . ',' . $message['Longitude'];
        D('WechatFans')->where(array('openid' => $openid))->save(array('position' => $position));

    }

    /**
     * 构造素材消息
     * @param  [type]
     * @param  integer
     * @return [distribute] 1表示普通消息，2表示关注时回复，3表示无索引回复
     */
    private function buildMessage(&$wechat, $extw = null)
    {
        $wechat_info = $wechat->getProperty('wechat_info');
        $company_uid = $wechat_info['company_uid'];
        $w           = "mpid=0 and state=1 and company_uid = " . $company_uid;
        $extw && $w .= ' and ' . $extw;
        $rs = (array) D('material')->where($w)->select();

        $replys = [];
        foreach ($rs as $v) {
            $replys[$v['type']][] = $v;
        }

        return $replys;
    }

    /**
     * 素材回复
     * @param  [type]
     * @param  [type]
     * @param  boolean
     * @return [type]
     */
    private function doMessage(&$wechat, $replys, $return = false)
    {
        $r;

        foreach ((array) $replys as $key => $v) {
            switch ($key) {
                case 'text':
                    $v[0]['info'] = json_decode($v[0]['info'], true);
                    $msg          = $this->getInjectMessage($wechat, $v[0]['info']);
                    $r[]          = $wechat->text($msg)->reply(null, $return);
                    break;
                case 'single':
                    $newsData;
                    foreach ($v as $v1) {
                        $item       = json_decode($v1['info'], true);
                        $newsData[] = array(
                            'Title'       => $item['title'],
                            'Description' => $item['introduction'],
                            'PicUrl'      => $this->fullServerPath($item['cover']),
                            'Url'         => $item['url'],
                        );
                    }
                    $r[] = $wechat->news($newsData)->reply(null, $return);
                    break;
                case 'image':
                    $media_id         = $this->getMediaId($v[0], $key, $wechat);
                    $media_id && $r[] = $wechat->image($media_id)->reply(null, $return);
                    break;
                case 'voice':

                    $media_id         = $this->getMediaId($v[0], $key, $wechat);
                    $media_id && $r[] = $wechat->voice($media_id)->reply(null, $return);
                    break;
                case 'video':
                    $media_id = $this->getMediaId($v[0], $key, $wechat);
                    $item     = json_decode($v[0]['info'], true);

                    $media_id && $r[] = $wechat->video($media_id, $item['title'], $item['desc'])->reply(null, $return);

                    break;
            }

        }
        return $r;

    }

    /**
     * 消息注入
     * @param  [type] $msg [description]
     * @return [type]      [description]
     */
    private function getInjectMessage(&$wechat, $msg)
    {
        if (strpos($msg, '{@nickname}') !== false) {
            $openid = $wechat->getProperty('openid');
            $r      = D('wechat_fans')->where(array('openid' => $openid))->getField('nick_name');
            $msg    = str_replace('{@nickname}', $r, $msg);
        }
        if (strpos($msg, '{@date}') !== false) {
            $openid = $wechat->getProperty('openid');
            $r      = D('wechat_fans')->where(array('openid' => $openid))->getField('follow_time');
            $msg    = str_replace('{@date}', substr($r, 0, 10), $msg);
        }

        if (strpos($msg, '{@openid}') !== false) {
            $openid = $wechat->getProperty('openid');
            $msg    = str_replace('{@openid}', $openid, $msg);
        }

        if (strpos($msg, '{@city}') !== false) {
            $openid = $wechat->getProperty('openid');
            $r      = D('wechat_fans')->where(array('openid' => $openid))->getField('region');
            $r      = $r == '-' ? '' : $r;
            $msg    = str_replace('{@city}', $r, $msg);
        }

        $msg = preg_replace_callback("/<a(.*?)<\/a>/is", function ($v) {
            $v[1] = str_replace(array('target="_blank"', '"'), array('', "'"), $v[1]);
            return '<a ' . $v[1] . '</a>';
        }, $msg);

        return $msg;
    }

    /**
     * 发送无索引回复
     * @param  [type]
     * @return [type]
     */
    private function doNoMessage(&$wechat)
    {
        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $replys      = $this->subscribeSource($wechat, 3);
        $replys && $this->sendMultipleMessage($wechat, $replys);
        $this->doCustomerService($wechat);

    }

    /**
     * 转发人工客服
     * @param  [type]
     * @return [type]
     */
    private function doCustomerService(&$wechat)
    {
        $wechat_info = $wechat->getProperty('wechat_info');
        $rules       = D('wechat_rule')->where(array('mpid' => $wechat_info['id']))->getField('rules');
        $rules       = json_decode($rules, true);

        switch ($rules['regong']) {
            case 2:
                //客服消息转发
                $wechat->transfer_customer_service()->reply();
                break;

            case 1:
                //客服消息转发
                $now_w = date('w');
                $now_t = date('H:i');
                if (($now_w >= $rules['t'][0] && $now_w <= $rules['t'][1]) && ($now_t >= $rules['t'][2] && $now_t <= $rules['t'][3])) {
                    $wechat->transfer_customer_service()->reply();
                }
                break;

        }
    }

    /**
     * @param  服务器完成路径
     * @return [type]
     */
    private function fullServerPath($path)
    {
        if (strpos($path, 'http') === false) {
            $path = 'http://' . $_SERVER['HTTP_HOST'] . '/' . ltrim($path, '/');
        }
        return $path;
    }

    /**
     * 生成素材文件在对应公众号媒体ID
     * @param  [type]
     * @param  [type]
     * @param  [type]
     * @return [type]
     */
    private function getMediaId($item, $type, &$wechat)
    {

        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $f           = D('WechatMedia')->where(array('material_id' => $item['id'], 'wechat_id' => $wechat_id))->find();

        if (!$f) {
            $info = json_decode($item['info'], true);

            $media_id = $this->uploadMedia($wechat, $info['file'], $type, $info);

            $info_media = array(
                'wechat_id'   => $wechat_id,
                'material_id' => $item['id'],
                'media_id'    => $media_id,
            );
            D('WechatMedia')->add($info_media);

        } elseif (!$f['media_id']) {
            $info = json_decode($item['info'], true);

            $media_id = $this->uploadMedia($wechat, $info['file'], $type, $info);

            $info_media = array(

                'media_id' => $media_id,
            );
            D('WechatMedia')->where(array('id' => $f['id']))->save($info_media);
        } else {
            $media_id = $f['media_id'];
        }
        return $media_id;

    }

    /**
     * 事件推送处理
     * @param  [type]
     * @return [type]
     */
    private function doEvent(&$wechat)
    {
        $message     = $wechat->getProperty('message');
        $openid      = $wechat->getProperty('openid');
        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $company_uid = $wechat_info['company_uid'];
        if (F('evnet_' . $openid . '_' . $message['CreateTime'])) {
            return false;
        } else {
            F('evnet_' . $openid . '_' . $message['CreateTime'], 1);
        }
        switch ($message['Event']) {
            case 'subscribe':
                $this->eventSubscribe($wechat);
                break;
            case 'SCAN':
                $this->qrcodeWithSubsribe($wechat,0);
                break;
            case 'unsubscribe':
                $rel = array(
                    'openid' => $openid,
                );
                $this->eventCancelSubcribe($rel);

                break;

            case 'CLICK':
                $eventKey = $message['EventKey'];
                $replys   = [];
                if (strpos($eventKey, 'material_') !== false) {
                    $material_id = str_replace('material_', '', $eventKey);
                    $replys_cfg  = $this->buildMenuMessage($material_id);

                }

                //附加点击事件
                $replys_click = $this->subscribeSource($wechat, 4);

                if ($replys_click) {
                    foreach ($replys_cfg as $k => $v) {
                        $replys[$k] = $v;
                        foreach ($replys_click as $k1 => $v1) {
                            if (isset($replys[$k1])) {
                                $replys[$k1] = array_merge($replys[$k], $v1);
                            } else {

                                $replys[$k1] = $v1;
                            }

                        }
                    }
                } else {
                    $replys = $replys_cfg;
                }

                $replys && $this->sendMultipleMessage($wechat, $replys, 1);

                break;

            case $wechat::EVENT_LOCATION:
                $this->doEventLocation($wechat);

        }
    }

    /**
     * @param  事件回复，获取素材
     * @return [type]
     */
    private function buildMenuMessage($id)
    {
        $rs                 = D('Material')->where(array('id' => $id))->find();
        $res[$rs['type']][] = $rs;
        return $res;
    }

    /**
     * 取消关注
     * @param  [type] $rel [description]
     * @return [type]      [description]
     */
    private function eventCancelSubcribe($rel)
    {
        # 取消关注
        $openid = $rel['openid'];
        D('WechatFans')->where(array('openid' => $openid))->save(
            array('follow_state' => 0, 'follow_time' => '')
        );

        $last_id = D('WechatQrfans')->where("openid='" . $openid . "'  ")->order('id desc')->getField('id');
        D('WechatQrfans')->where(array('id'=>$last_id))->save(array('canceled' => time(), 'is_unsubsribe' => 1));

    }

    /**
     * 关注
     * @param  [type] $rel     [description]
     * @param  [type] &$wechat [description]
     * @return [type]          [description]
     */
    private function eventSubscribe(&$wechat)
    {
        $message = $wechat->getProperty('message');
        if ($message['EventKey']) {
            $this->qrcodeWithSubsribe($wechat,1);
        } else {
            $this->onlySubscribe($wechat);
        }
        $this->subscribeUserAdd($wechat);

    }

    /**
     * 普通关注
     * @return [type] [description]
     */
    private function onlySubscribe(&$wechat)
    {
        $message     = $wechat->getProperty('message');
        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $company_uid = $wechat_info['company_uid'];
        $openid      = $wechat->getProperty('openid');
        $replys      = $this->subscribeSource($wechat, 2);
        $replys && $this->sendMultipleMessage($wechat, $replys);

    }

    /**
     * 发送多条信息处理
     * @param  [type] &$wechat [description]
     * @param  [type] $replys  [description]
     * @return [type]          [description]
     */
    private function sendMultipleMessage(&$wechat, $replys)
    {
        $openid = $wechat->getProperty('openid');
        if ($this->countTwoArray($replys) > 1) {
            $wechat->setMessageEncrypType(''); //必须明文
            $ls_all = [];
            array_walk($replys, function ($v) use (&$ls_all) {
                foreach ($v as $v1) {
                    $ls_all[] = $v1;
                }
            });

            $info_new;

            foreach ($ls_all as $v) {
                $info_new[$v['type']][0] = $v;
                $xml                     = $this->doMessage($wechat, $info_new, true);
                unset($info_new[$v['type']]);
                foreach ($xml as $rv) {
                    $rv           = xmlToArr($rv);
                    $rv['touser'] = $openid;
                    $info_send    = $this->replyToService($rv);
                    $wechat->sendCustomMessage($info_send);
                }
                sleep(1);
            }
        } else {
            $this->doMessage($wechat, $replys);

        }
    }

    /**
     * 统计二维数组元素
     * @return [type] [description]
     */
    private function countTwoArray($ar)
    {
        if (!$ar) {
            return 0;
        }

        $i = 0;
        foreach ($ar as $v) {
            foreach ((array) $v as $v1) {
                $i++;
            }
        }
        return $i;
    }

    /**
     * 二维码扫关注
     * @return [type] [description]
     */
    private function qrcodeWithSubsribe(&$wechat,$qrtype=0)
    {

        $message     = $wechat->getProperty('message');
        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $company_uid = $wechat_info['company_uid'];
        $openid      = $wechat->getProperty('openid');
        //扫码事件
        $qrcode   = $message['EventKey'];
        $scene_id = str_replace('qrscene_', '', $message['EventKey']);
        //处理用户标签
        $this->doUserTags($scene_id, $wechat);

        $f      = D('WechatQrfans')->where(array('openid' => $openid, 'qrtype' => 1))->find();
        $is_new = $f ? 0 : 1;
        D('WechatQrfans')->add(array(
            'wechat_id' => $wechat_id,
            'openid'    => $openid,
            'qrscene'   => $scene_id,
            'created'   => $message['CreateTime'],
            'qrtype'    => $qrtype,
            'is_new'    => $is_new,
        ));

        //回复消息
        $replys = $this->qrcodeSource($wechat, $scene_id);

        $replys && $this->sendMultipleMessage($wechat, $replys);

    }

    /**
     * 二维码数据源
     * @param  [type] &$wechat  [description]
     * @param  [type] $scene_id [description]
     * @return [type]           [description]
     */
    private function qrcodeSource(&$wechat, $scene_id)
    {
        $r = D('wechat_qrcode')->where(array('id' => $scene_id))->getField('reply');
        if ($r) {
            $r = json_decode($r, true);
            if ($r['enable'] && $r['material']) {
                $r['material'] = json_decode($r['material'], true);
                $ids           = getByField($r['material'], 'id', 'str');
                $materials     = D('Material')->where("id in (" . $ids . ") and state=1 ")->getField('id,type,title,info');
                foreach ($r['material'] as $v) {
                    $item = $materials[$v['id']];
                    if (array_sum($v['donation_target']) > 0) {
                        $item['donation_target'] = $v['donation_target'];
                        $item['outoftime']       = $r['cycle_start'] . ',' . $r['cycle_end'];
                        $this->dispatcherService($wechat, $item);
                    } else {
                        $replys[$item['type']][] = $item;
                    }
                }
            }
        }
        return $replys;
    }

    /**
     * 关注用户添加
     * @return [type] [description]
     */
    private function subscribeUserAdd(&$wechat)
    {
        $wechat_info          = $wechat->getProperty('wechat_info');
        $wechat_id            = $wechat_info['id'];
        $company_uid          = $wechat_info['company_uid'];
        $openid               = $wechat->getProperty('openid');
        $userinfo             = $wechat->getUserInfo($openid);
        $userinfo['nickname'] = $wechat->getDefaultVal($userinfo['nickname'], '网友');
        $userinfo['avatar']   = $wechat->getDefaultVal($this->downloadAvatar($userinfo['headimgurl'], $openid, 'upload/Wechat/' . $wechat_id . '/avatar/'), '');

        $ex   = D('WechatFans')->where(array('openid' => $openid))->field('id,openid')->find();
        $data = array(
            'cid'          => $wechat_id,
            'nick_name'    => $userinfo['nickname'],
            'avatar'       => $userinfo['avatar'],
            'sex'          => (int) $userinfo['sex'] - 1,
            'region'       => $userinfo['province'] . '-' . $userinfo['city'],
            'follow_time'  => date('Y-m-d H:i:s'),
            'update_time'  => date('Y-m-d H:i:s'),
            'num_state'    => 1,
            'openid'       => $openid,
            'company_uid'  => $company_uid,
            'follow_state' => 1,
            'groupid'      => $userinfo['groupid'],
            'tagid_list'   => json_encode($userinfo['tagid_list'], JSON_UNESCAPED_UNICODE),
        );
        if (!$ex) {
            D('WechatFans')->add($data);

        } else {
            unset($data['openid']);
            unset($data['num_state']);
            D('WechatFans')->where(array('id' => $ex['id']))->save($data);
        }
    }

    /**
     * 处理用户标签
     * @param  [type] $scene_id [description]
     * @param  [type] &$wechat  [description]
     * @return [type]           [description]
     */
    private function doUserTags($scene_id, &$wechat)
    {
        $scene  = D('wechat_qrcode')->where(array('id' => $scene_id))->find();
        $rule   = json_decode($scene['rule'], true);
        $openid = $wechat->getProperty('openid');
        $tags   = $rule['tag1'];
        if ($rule['type'] != 2) {
            switch ($rule['type']) {
                case 1:
                    $old_tags = (array) $wechat->getUserTag($openid);
                    $new_tags = array_merge($tags, $old_tags);
                    $new_tags = array_unique($new_tags);
                    break;
                case 3:
                    $old_tags = (array) $wechat->getUserTag($openid);
                    foreach ($old_tags as $tagid) {
                        $wechat->cancelUserTag(array($openid), $tagid);
                    }
                    $new_tags = $tags;
                    break;
            }

            $r = [];

            foreach ($new_tags as $v) {
                $r[] = $wechat->addUserLabel(array($openid), $v);
            }
            $this->changeFansTag($openid, $new_tags);
        }

    }

    private function changeFansTag($openid, $tags)
    {
        $tags = json_encode($tags);
        D('wechat_fans')->where(array('openid' => $openid))->save(array('tagid_list' => $tags));
    }

    public function updateFansTagsApi($wechat_id, $openid, $new_tags)
    {

        $info_wechat = D('Wechat')->where(array('id' => $wechat_id))->find();

        $options = array(
            'appid'                    => $info_wechat['wechat_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );

        $wechat = \TPOpenWechat::getInstance($options);

        $old_tags = (array) $wechat->getUserTag($openid);
        foreach ($old_tags as $tagid) {
            $wechat->cancelUserTag(array($openid), $tagid);
        }

        foreach ($new_tags as $v) {
            $r[] = $wechat->addUserLabel(array($openid), $v);
        }
        return $r;

    }

    /**
     * 延迟发送客服消息
     * @param  [type]
     * @return [type]
     */
    private function dispatcherService(&$wechat, $item)
    {
        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $openid      = $wechat->getProperty('openid');
        $now         = time();

        $target = explode('-', $item['donation_target']);
        $target = $target[0] * 3600 + $target[1] * 60 + $target[2];
        $item   = array(
            'wechat_id'   => $wechat_id,
            'sendtime'    => $now + $target,
            'material_id' => $item['id'],
            'openid'      => $openid,
            'outoftime'   => $item['outoftime'],
        );
        D('WechatServiceMessage')->add($item);

    }

    /**
     * 关注时回复消息提取
     * @param  [type]
     * @param  [mtype] 2关注是回复，3表示无索引回复,4点击回复
     * @return [type]
     */
    private function subscribeSource(&$wechat, $mtype)
    {
        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $main        = D('wechat_rule')->where(array('mpid' => $wechat_id))->find();
        $cfg         = array(2 => 'subscribe', 3 => 'noindex', 4 => 'clickmenu');
        $r           = $main[$cfg[$mtype]];
        $replys      = [];
        if ($r) {
            $r           = json_decode($r, true);
            $main['cfg'] = $r;
            $replys      = call_user_func(array(&$this, "subscribeSource" . $mtype), $wechat, $main);

        }

        return $replys;
    }

    /**
     * 发送关注时回复
     * @param  [type] &$wechat [description]
     * @param  [type] $main    [description]
     * @return [type]          [description]
     */
    private function subscribeSource2(&$wechat, $main)
    {
        $r      = $main['cfg'];
        $replys = [];
        if ($r['enable'] && $r['material']) {
            $r['material'] = json_decode($r['material'], true);
            $ids           = getByField($r['material'], 'id', 'str');
            $materials     = D('Material')->where("id in (" . $ids . ") and state=1 ")->getField('id,type,title,info');
            foreach ($r['material'] as $v) {
                $item = $materials[$v['id']];
                if (array_sum($v['donation_target']) > 0) {
                    $item['donation_target'] = $v['donation_target'];
                    $item['outoftime']       = $r['cycle_start'] . ',' . $r['cycle_end'];
                    $this->dispatcherService($wechat, $item);
                } else {
                    $replys[$item['type']][] = $item;
                }
            }
        }
        return $replys;
    }

    /**
     * 发送无索引回复
     * @param  [type] &$wechat [description]
     * @param  [type] $main    [description]
     * @return [type]          [description]
     */
    private function subscribeSource3(&$wechat, $main)
    {
        $r      = $main['cfg'];
        $replys = [];
        if ($r['enable'] && $r['material']) {
            $r['material'] = json_decode($r['material'], true);
            $ids           = getByField($r['material'], 'id', 'str');
            $materials     = D('Material')->where("id in (" . $ids . ") and state=1 ")->getField('id,type,title,info');
            foreach ($r['material'] as $v) {
                $item                    = $materials[$v['id']];
                $replys[$item['type']][] = $item;
            }
        }
        return $replys;
    }

    /**
     * 发送菜单点击消息
     * @param  [type] &$wechat [description]
     * @param  [type] $main    [description]
     * @return [type]          [description]
     */
    private function subscribeSource4(&$wechat, $main)
    {
        $r           = $main['cfg'];
        $openid      = $wechat->getProperty('openid');
        $wechat_info = $wechat->getProperty('wechat_info');
        $wechat_id   = $wechat_info['id'];
        $hour        = $r['cycle']['hour'];
        $timers      = $r['cycle']['times'];
        if (!$hour || !$timers) {
            return false;
        }

        $end    = time() - $hour * 3600;
        $has    = D('wechat_clickmenu_log')->where(array('openid' => $openid, 'created' => array('gt', $end)))->count();
        $replys = [];
        if ($r['enable'] && $r['material'] && ($has < $timers)) {
            D('wechat_clickmenu_log')->add(array(
                'openid'    => $openid,
                'created'   => time(),
                'wechat_id' => $wechat_id,
            ));
            $r['material'] = json_decode($r['material'], true);
            $ids           = getByField($r['material'], 'id', 'str');
            $materials     = D('Material')->where("id in (" . $ids . ") and state=1 ")->getField('id,type,title,info');
            foreach ($r['material'] as $v) {
                $item                    = $materials[$v['id']];
                $replys[$item['type']][] = $item;
            }
        }
        return $replys;
    }

    /**
     * 第三方授权处理
     * @return [type]
     */
    public function authCallback()
    {

        $msg        = '授权失败，请重新操作！';
        $auth_code  = I('get.auth_code');
        $companyuid = I('get.companyuid');
        $data       = array(
            'component_appid'    => $this->component_appid,
            'authorization_code' => $auth_code,
        );
        $r = curlRequest('https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=' . $this->getComponentAccessToken(), $data);
        if ($r) {
            $r = json_decode($r, true);
            //入库
            D('WechatOpen')->saveAuthor($r);
            //初始单公众号缓存
            $appid    = $r['authorization_info']['authorizer_appid'];
            $authname = 'wechat_access_token' . $appid;
            //创建token缓存
            S($authname, $r['authorization_info']['authorizer_access_token'], 7000);

            //保存公众号信息
            $wechatInfo               = $this->getWechatInfo($appid);
            $wechatInfo['companyuid'] = $companyuid;
            $wechatInfo && D('WechatOpen')->saveWechat($wechatInfo);

            $msg = '授权完成,请关闭本页面！';
            $this->success($msg, '/');

        } else {
            $this->error($msg, '/');
        }

    }

    /**
     * @param  获取公众号消息
     * @return [type]
     */
    private function getWechatInfo($appid)
    {
        $data = array(
            'component_appid'  => $this->component_appid,
            'authorizer_appid' => $appid,
        );
        $r = curlRequest('https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=' . $this->getComponentAccessToken(), $data);
        if ($r) {
            $r = json_decode($r, true);

            $r['authorizer_info']['qrcode_url'] = $this->downloadImageFromUrl($r['authorizer_info']['qrcode_url'], 'Upload/wechat/qrcode/');

        }
        return $r;
    }




     /**
     * @param  获取公众号授权消息
     * @return [type]
     */
    public  function getPublicWechatInfo()
    {   
        $appid = I("get.appid");
        $data = array(
            'component_appid'  => $this->component_appid,
            'authorizer_appid' => $appid,
        );
        $r = curlRequest('https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=' . $this->getComponentAccessToken(), $data);
        echo "<pre>";
        print_r($r);
    }



    /**
     * 突破防盗链抓取图片
     * @param  [type]
     * @param  string
     * @return [type]
     */
    private function downloadImageFromUrl($url, $path = "./Upload/wechat/qrcode/")
    {
        // 因为不知道最后接受到的文件是什么格式，先建立一个临时文件，用于保存
        $tmpFile = tempnam(sys_get_temp_dir(), 'image');

        # 文件下载 BEGIN #

        // 打开临时文件，用于写入（w),b二进制文件
        $resource = fopen($tmpFile, 'wb');

        // 初始化curl
        $curl = curl_init($url);
        // 设置输出文件为刚打开的
        curl_setopt($curl, CURLOPT_FILE, $resource);
        // 不需要头文件
        curl_setopt($curl, CURLOPT_HEADER, 0);
        // 执行
        curl_exec($curl);
        // 关闭curl
        curl_close($curl);

        // 关闭文件
        fclose($resource);

        # 文件下载 END #

        // 获取文件类型
        if (function_exists('exif_imagetype')) {
            // 读取一个图像的第一个字节并检查其签名(这里需要打开mbstring及php_exif)
            $fileType = exif_imagetype($tmpFile);
        } else {
            // 获取文件大小，里面第二个参数是文件类型 （这里后缀可以直接通过getimagesize($url)来获取，但是很慢）
            $fileInfo = getimagesize($tmpFile);
            $fileType = $fileInfo[2];
        }

        // 根据文件类型获取后缀名
        $extension = image_type_to_extension($fileType);

        // 计算指定文件的 MD5 散列值，作为保存的文件名，重复下载同一个文件不会产生重复保存，相同的文件散列值相同
        $md5FileName = md5_file($tmpFile);

        // 最终保存的文件
        $returnFile = $path . $md5FileName . $extension;

        // 检查传过来的路径是否存在，不存在就创建
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }

        // 复制临时文件到最终保存的文件中
        copy($tmpFile, $returnFile);

        // 释放临时文件
        @unlink($tmpFile);

        // 返回保存的文件路径
        return '/' . ltrim($returnFile, './');
    }

    /**
     * 刷新公众号token
     * @return [type]
     */
    public function refreshAuthToken()
    {
        $id   = I('get.id/d');
        $info = D('WechatOpen')->where('wechat_id=' . $id)->find();
        $data = array(
            'component_appid'          => $this->component_appid,
            'authorizer_appid'         => $info['authorizer_appid'],
            'authorizer_refresh_token' => $info['authorizer_refresh_token'],
        );

        $r = curlRequest('https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=' . $this->getComponentAccessToken(), $data);

        if ($r) {
            $r = json_decode($r, true);
            if (!$r['errmsg']) {

                $update = array('authorizer_access_token' => $r['authorizer_access_token'], 'authorizer_refresh_token' => $r['authorizer_refresh_token']);
                D('WechatOpen')->where(array('wechat_id' => $id))->save($update);

                $this->success('刷新成功！', '/');
            } else {
                $this->error('刷新失败！', '/');
            }

        } else {
            $this->error('刷新失败！', '/');
        }

    }

    /**
     * 获取公众号缓存信息
     * @param  [type] $wechat_id [description]
     * @param  string $field     [description]
     * @return [type]            [description]
     */
    private function getWechatCache($wechat_id, $field = '')
    {
        $key = 'wechat_cache_' . $wechat_id;
        if (!F($key)) {
            $cache = D('wechat')->where(array('id' => $wechat_id))->find();
            F($key, $cache);
        } else {
            $cache = F($key);
        }
        $res = $field ? $cache[$field] : $cache;
        return $res;
    }

    /**
     * 抓取公众号粉丝
     * @return [type]
     */
    public function fetchFans($wechat_id)
    {

        $wechat_info = $this->getWechatCache($wechat_id);

        $authorizer_appid = $wechat_info['wechat_appid'];
        $info             = D('WechatOpen')->where("authorizer_appid='" . $authorizer_appid . "'")->find();

        $options = array(
            'appid'                    => $info['authorizer_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );

        $wechat      = \TPOpenWechat::getInstance($options);
        $flag        = 1;
        $ls          = [];
        $next_openid = '';
        //获取标签

        $tags = $wechat->getUserTags();

        $this->saveWechatTags($tags, $wechat_id);

        while ($flag == 1) {
            $users = $wechat->getUserList($next_openid);

            $next_openid = $users['next_openid'];
            if (!$users['data']) {
                $flag = 0;
                break;
            } else {
                $ls = array_merge($ls, $users['data']['openid']);
            }
        }
        foreach ($ls as $openid) {
            $userinfo = $wechat->getUserInfo($openid);
            $f        = D('WechatFans')->where(array('openid' => $openid))->field('openid')->find();
            $item     = array(
                'cid'          => $wechat_id,
                'nick_name'    => $userinfo['nickname'],
                'avatar'       => $this->downloadAvatar($userinfo['headimgurl'], $openid, 'upload/Wechat/' . $wechat_id . '/avatar/'),
                'sex'          => (int) $userinfo['sex'] - 1,
                'region'       => $userinfo['province'] . '-' . $userinfo['city'],
                'follow_time'  => date('Y-m-d H:i:s', $userinfo['subscribe_time']),
                'update_time'  => date('Y-m-d H:i:s'),
                'num_state'    => 1,
                'openid'       => $openid,
                'company_uid'  => $wechat_info['company_uid'],
                'follow_state' => 1,
                'groupid'      => $userinfo['groupid'],
                'tagid_list'   => json_encode($userinfo['tagid_list'], JSON_UNESCAPED_UNICODE),
            );
            if (!$f) {
                D('WechatFans')->add($item);

            } else {
                unset($item['num_state']);
                unset($item['openid']);
                D('WechatFans')->where(array('openid' => $openid))->save($item);

            }
            sleep(0);
        }

        return true;

    }

    /**
     * 获取用户标签
     * @param  [type] $wechat_id [description]
     * @return [type]            [description]
     */
    public function getUserTags($wechat_id)
    {
        $info_wechat = D('Wechat')->where(array('id' => $wechat_id))->find();

        $options = array(
            'appid'                    => $info_wechat['wechat_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );

        $wechat = \TPOpenWechat::getInstance($options);

        $tags = $wechat->getUserTags();

        $this->saveWechatTags($tags, $wechat_id);

        return $tags;
    }

    private function saveWechatTags($tags, $wechat_id)
    {
        if ($tags) {
            foreach ($tags as $v) {
                $item = array(
                    'wechat_id' => $wechat_id,
                    'tag_id'    => $v['id'],
                    'tag_name'  => $v['name'],
                    'count'     => $v['count'],
                );
                $f = D('WechatTags')->where(array('wechat_id' => $wechat_id, 'tag_id' => $v['id']))->find();
                if (!$f) {
                    D('WechatTags')->add($item);
                } else {
                    unset($item['tag_id']);
                    unset($item['wechat_id']);
                    D('WechatTags')->where(array('wechat_id' => $wechat_id, 'tag_id' => $v['id']))->save($item);
                }

            }
        }
    }

    /**
     * 已授权公众号列表查询
     * @return [type]
     */
    public function authedList()
    {

        $data = array(
            'component_appid' => $this->component_appid,
            'offset'          => 0,
            'count'           => 100,
        );
        $url = 'https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=' . $this->getComponentAccessToken();
        $r   = curlRequest($url, $data);
        echo "<pre>";
        print_r($r);
        echo "<pre>";
        exit;

    }

    /**
     *  保存多媒体资源
     * @param  [type] $wechat_id [description]
     * @param  [type] $file      [description]
     * @param  [type] $type      [description]
     * @return [type]            [description]
     */
    private function uploadMedia(&$wechat, $file, $type = 'image', $info = null)
    {

        $fdata = array('media' => '@' . realpath(ltrim($file, '/')));

        $video_info = [];
        if ($type == 'video') {
            $video_info = array('title' => $info['title'], 'introduction' => $info['desc']);
        }

        $r = $wechat->uploadForeverMedia($fdata, $type, $video_info);

        return $r;

    }
    /**
     * 下载用户头像
     * @param  [type]
     * @param  [type]
     * @param  string
     * @return [type]
     */
    private function downloadAvatar($f, $openid, $path = 'Upload/Wechat/avatar/')
    {

        if (!is_dir($path)) {
            $this->mkDirs($path);
        }
        $h = $this->curlGetFile($f);
        if ($h) {
            $newf = $path . $openid . '.jpg';
            @file_put_contents($newf, $h);
            unset($h);
        } else {
            $newf = $f;
        }
        return $newf;
    }

    /**
     * 创建目录
     * @param  [type]
     * @return [type]
     */
    private function mkDirs($dir)
    {
        if (!is_dir($dir)) {
            if (!$this->mkDirs(dirname($dir))) {
                return false;
            }
            if (!mkdir($dir, 0777)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 抓取图片
     * @param  [type]
     * @return [type]
     */
    private function curlGetFile($url)
    {

        $headers[] = 'Origin: http://data.jingzhunshuju.com';
        $headers[] = 'Referer: http://data.jingzhunshuju.com';
        $headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3702.0 Safari/537.36';

        $ch = curl_init();

        $opt = array();

        $opt[CURLOPT_URL] = $url;

        $opt[CURLOPT_HEADER] = false;

        $opt[CURLOPT_CONNECTTIMEOUT] = 15;

        $opt[CURLOPT_TIMEOUT] = 15;

        $opt[CURLOPT_AUTOREFERER] = true;

        $opt[CURLOPT_USERAGENT] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11';

        $opt[CURLOPT_RETURNTRANSFER] = true;

        $opt[CURLOPT_FOLLOWLOCATION] = true;

        $opt[CURLOPT_MAXREDIRS] = 10;
        //user defined opt

        if (!empty($opt)) {
            foreach ($opt as $k => $v) {
                $opt[$k] = $v;
            }
        }

        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书
        curl_setopt_array($ch, $opt);
        $r = curl_exec($ch);
        unset($ch);

        return $r;
    }

    /**
     * 发送客服消息
     * @return [type] [description]
     */
    public function sendServiceMessage()
    {
        $now    = time();
        $needed = D('WechatServiceMessage')->where(array('sendtime' => array('ELT', $now), 'sended' => 0))->select();
        $needed = $this->disturb($needed);
        if ($needed) {
            foreach ($needed as $v) {
                $ids_material[] = $v['material_id'];
                $ids_wechats[]  = $v['wechat_id'];
            }

            $materials = D('Material')->where(array('id' => array('in', $ids_material)))->getField('id,type,info');
            $wechats   = D('Wechat')->where(array('id' => array('in', $ids_wechats)))->getField('id,wechat_appid');
            $ls;
            foreach ($needed as $v) {
                $ls[$v['wechat_id']][$v['openid']][] = $v;
            }

            foreach ($ls as $k => $v) {
                $options = array(
                    'appid'                    => $wechats[$k], //填写高级调用功能的密钥

                    'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
                    'component_token'          => $this->component_token, //填写高级调用功能的密钥
                    'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
                    'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
                );
                $ws = new \TPOpenWechat($options);

                $wechat_info = D('Wechat')->where(array('id' => $k))->field('id,company_uid')->find();
                $ws->setProperty(array(
                    'openid'      => $k,
                    'wechat_info' => $wechat_info,
                ));
                $ws->setMessageEncrypType(''); //必须明文

                foreach ($v as $k1 => $v1) {
                    $replys = [];
                    foreach ($v1 as $v2) {
                        $temp                    = $materials[$v2['material_id']];
                        $replys[$temp['type']][] = $temp;
                    }

                    $xml = $this->doMessage($ws, $replys, true);
                    foreach ($xml as $rv) {
                        $rv           = xmlToArr($rv);
                        $rv['touser'] = $k1;
                        $info_send    = $this->replyToService($rv);
                        $ws->sendCustomMessage($info_send);
                    }

                    D('WechatServiceMessage')->where(array('openid' => $k1))->save(array('sended' => 1));

                }
                unset($ws);
            }

        }
        $this->success('关注时延时回复发送成功！', "javascript:window.opener=null;window.close();");
    }

    private function disturb($r)
    {
        $now = date('Y-m-d H:i');
        foreach ($r as $k => $v) {
            if (!$v['outoftime']) {
                continue;
            }

            $timer = explode(',', $v['outoftime']);
            $start = date('Y-m-d') . ' ' . $timer[0];
            $end   = $timer[1] > $timer[0] ? date('Y-m-d') . ' ' . $timer[0] : date('Y-m-d', strtotime('+1 day')) . ' ' . $timer[0];
            if ($now > $start && $now < $end) {
                unset($r[$k]);
            }

        }
        return $r;
    }

    /**
     * 格式化客服消息
     * @param  [type]
     * @return [type]
     */
    private function replyToService($r)
    {

        switch ($r['MsgType']) {
            case 'text':
                $info_send = array(
                    'touser'  => $r['touser'],
                    'msgtype' => 'text',
                    'text'    => array('content' => $r['Content']),
                );
                break;

            case 'image':
                $info_send = array(
                    'touser'  => $r['touser'],
                    'msgtype' => 'image',
                    'image'   => array('media_id' => $r['Image']['MediaId']),
                );
                break;
            case 'news':

                $news               = [];
                $temp               = isset($r['Articles']['item'][0]) ? $r['Articles']['item'][0] : $r['Articles']['item'];
                $news['articles'][] =
                array("title" => $temp['Title'],
                    "description" => $temp['Description'],
                    "url"         => $temp['Url'],
                    "picurl"      => $temp['PicUrl'],
                );

                $info_send = array(
                    'touser'  => $r['touser'],
                    'msgtype' => $r['MsgType'],
                    'news'    => $news,
                );

                break;

            case 'voice':
                $info_send = array(
                    'touser'  => $r['touser'],
                    'msgtype' => 'voice',
                    'voice'   => array('media_id' => $r['Voice']['MediaId']),
                );
                break;

            case 'video':

                $info_send = array(
                    'touser'  => $r['touser'],
                    'msgtype' => 'video',
                    'video'   => array(
                        'media_id'    => $r['Video']['MediaId'],
                        "title"       => "视频消息",
                        "description" => "",
                    ),
                );

                break;

        }
        return $info_send;
    }

    /**
     * 生成场景二维码
     * @param  [type]
     * @param  [type]
     * @param  [type]
     * @param  string
     * @return [type]
     */
    public function createQr($wechat_id, $scene_id, $stype, $time = '')
    {

        $type        = $stype == 1 ? 0 : 2;
        $info_wechat = D('Wechat')->where(array('id' => $wechat_id))->find();
        $options     = array(
            'appid'                    => $info_wechat['wechat_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );

        $wechat = \TPOpenWechat::getInstance($options);
        $expire = strtotime($time) - time();
        if ($expire <= 0) {
            $expire = 1;
        }

        $r = $wechat->getQRCode($scene_id, $type, $expire);

        return $r;

    }

    /**
     * 提交标签
     * @param  [type] $wechat_id [description]
     * @param  [type] $tags      [description]
     * @return [type]            [description]
     */
    public function postTags($wechat_id, $tags)
    {
        $info_wechat = D('Wechat')->where(array('id' => $wechat_id))->find();
        $options     = array(
            'appid'                    => $info_wechat['wechat_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );

        $wechat = \TPOpenWechat::getInstance($options);
        $r      = $wechat->createTags($tags);

        return $r;
    }

    /**
     * 菜单同步处理
     * @param  [type]
     * @param  [type]
     * @return [type]
     */
    public function syncMenu($wechat_id, $menu)
    {
        $info_wechat = D('Wechat')->where(array('id' => $wechat_id))->find();
        $options     = array(
            'appid'                    => $info_wechat['wechat_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );
        $wechat = \TPOpenWechat::getInstance($options);
        $r      = $wechat->createMenu($menu);
        return $r;
    }

    /**
     * 主动发送客服消息，客服对话
     * @param  [type]
     * @param  [type]
     * @return [type]
     */
    public function sendDialogMessage($msg, $openid)
    {

        $info = D('wechat_fans')->where(array('openid' => $openid))->find();

        $wechat_id = $info['cid'];

        $info_wechat = D('Wechat')->where(array('id' => $wechat_id))->find();
        $options     = array(
            'appid'                    => $info_wechat['wechat_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );

        $wechat = \TPOpenWechat::getInstance($options);
        $wechat->setProperty(array(
            'openid'      => $openid,
            'wechat_info' => $info_wechat,
        ));

        if (is_string($msg)) {
            //默认文本类型
            $rv = array(
                'MsgType' => 'text',
                'touser'  => $openid,
                'Content' => $msg,
            );
        } else {
            $replys;
            $replys[$msg['type']][] = $msg;
            $xml                    = $this->doMessage($wechat, $replys, true);

            $rv           = xmlToArr($xml[0]);
            $rv['touser'] = $openid;

        }

        $info_send = $this->replyToService($rv);

        if (is_array($msg) && $msg['material_id']) {
            $material_title    = D('material')->where(array('id' => $msg['material_id']))->getField('title');
            $rv['Content']     = '素材回复【ID:' . $msg['material_id'] . '，标题：' . $material_title . '】';
            $rv['material_id'] = $msg['material_id'];
        }

        $log = array(
            'info_type' => $rv['MsgType'],
            'openid'    => $openid,
            'created'   => date('Y-m-d H:i:s'),
            'wechat_id' => $wechat_id,
            'isrec'     => 2,
            'message'   => json_encode($rv, JSON_UNESCAPED_UNICODE),
        );
        D('wechat_message')->add($log);
        $r = $wechat->sendCustomMessage($info_send);
        return $r;

    }

    /**
     * 扫码登录
     * @return [type] [description]
     */
    public function qrScanLogin()
    {
        $code = I('get.code');
        $msg  = '授权失败，请先登陆后台绑定!';
        if ($code) {
            //第三方网页应用appid
            $appid  = 'wx68c4fd52257e1f43';
            $secret = 'e2501ed1f10bcb4bb3a11df86a57e9e3';
            $url    = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $appid . '&secret=' . $secret . '&code=' . $code . '&grant_type=authorization_code';
            $r      = http_get($url);
            if ($r) {
                $r        = json_decode($r, true);
                $f        = D('wechat_login')->where(array('openid' => $r['openid']))->find();
                $member   = session("store_member_auth");
                $memberId = $member['uid'];
                if ($memberId) {
                    if (!$f) {
                        $ex = D('wechat_login')->where(array('staff_id' => $memberId))->find();
                        if (!$ex) {
                            D('wechat_login')->add(array(
                                'staff_id' => $memberId,
                                'openid'   => $r['openid'],
                                'unionid'  => $r['unionid'],
                                'created'  => date('Y-m-d H:i:s'),
                            ));
                        } else {
                            D('wechat_login')->where(array('staff_id' => $memberId))->save(array(
                                'openid'  => $r['openid'],
                                'unionid' => $r['unionid'],
                                'created' => date('Y-m-d H:i:s'),
                            ));
                        }
                        $msg = '绑定成功！';
                    } else {
                        $msg = '您已绑定过了！';
                    }
                } elseif ($f) {

                    $user = D('StoreStaff')->where(array('uid' => $f['staff_id']))->find();
                    if ($user) {
                        $msg = '登陆成功！';
                        D('StoreStaff')->wechatScanLogin($user);
                    } else {
                        $msg = '请到会员中心绑定！';
                    }
                }

            }
            $this->success($msg, '/storeadmin.php');

        } else {
            $this->error($msg, '/storeadmin.php');
        }

    }

    /**
     * 远程上传素材到公众号
     * @return [type] [description]
     */
     public function uploadForeverArticles()
    {
        $post = I('post.');
        $wechat_id   = $post['wechat_id'];
        $wechat_info = $this->getWechatCache($wechat_id);
        $options = array(
            'appid'                    => $wechat_info['wechat_appid'], //填写高级调用功能的密钥

            'component_appid'          => $this->component_appid, //填写高级调用功能的密钥
            'component_token'          => $this->component_token, //填写高级调用功能的密钥
            'component_access_token'   => $this->getComponentAccessToken(), //填写高级调用功能的app id
            'component_encodingAesKey' => $this->component_encodingAesKey, //填写高级调用功能的app id
        );
        $wechat              = \TPOpenWechat::getInstance($options);
        $infos['articles'][] = array(
            'title'                 => $post['title'],
            'thumb_media_id'        => $this->uploadMedia($wechat, $post['thumb'], 'image'),
            'author'                => $post['author'],
            'digest'                => $post['digest'],
            'content'               => $post['content'],
            'content_source_url'    => $post['url'],
            'need_open_comment'     => (int)$post['need_open_comment'],
            'only_fans_can_comment' => (int)$post['only_fans_can_comment'],
        );
        $r = $wechat->uploadForeverArticles($infos);
        return $r;

    }

}
